#include <windows.h>
#include <iostream>
#include "opencv2/myopencv.hpp"
#include "NuiApi.h"
#pragma comment(lib, "Kinect10.lib")

using namespace std;

INuiSensor *m_pNuiSensor; 









class DepthPlayer{
public:
	FILE* fin;
	long long startFilePos;
	long long fileSize;
	int w, h;
	int frameNum;
	int curFrame;
	int frameSize;
	int seconds;
	short* frame;
	CvMat* mat;
	CvMat* newmat;
	CvMat* backup;
	bool isSkipTo;
	int restart;
	bool pause;
	DepthPlayer() {
		fin = NULL;
		startFilePos = fileSize = 0;
		w = h = 0;
		frameNum = curFrame = frameSize = 0;
		seconds = 0;
		frame = NULL;
		mat = newmat = backup = NULL;
		isSkipTo = true;
		restart = 0;
		pause = false;
	}

	void initParamter(int width, int height) {
		w = width;
		h = height;
		frameSize = w*h*sizeof(short);

		frame = new short[w*h];
		mat = cvCreateMatHeader(h, w, CV_16SC1);
		newmat = cvCreateMat(h, w, CV_64FC1);
		backup = cvCreateMat(h, w, CV_16SC1);
		cvZero(backup);
	}

	void showFrame(bool useUpdate = true) {
		if (useUpdate) updateMat();
		cvShowImage("depth tracking", mat);
		cvWaitKey(1000/60);
	}

	void myflip( const uchar* src, size_t sstep, uchar* dst, size_t dstep, cv::Size size, size_t esz )
	{
		int i, j, limit = (int)(((size.width + 1)/2)*esz);
		cv::AutoBuffer<int> _tab(size.width*esz);
		int* tab = _tab;

		for( i = 0; i < size.width; i++ )
			for( size_t k = 0; k < esz; k++ )
				tab[i*esz + k] = (int)((size.width - i - 1)*esz + k);

		for( ; size.height--; src += sstep, dst += dstep )
		{
			for( i = 0; i < limit; i++ )
			{
				j = tab[i];
				uchar t0 = src[i], t1 = src[j];
				dst[i] = t1; dst[j] = t0;
			}
		}
	}

	void updateMat(void) {
		mat->data.s = frame;
		cv::Mat src = cv::Mat(mat);
		size_t esz = src.elemSize();
		myflip( src.data, src.step, src.data, src.step, src.size(), esz );
		// 		cvSmooth(mat, mat);
		// 		cvFlip(mat, NULL, 1);
	}

	~DepthPlayer() {
		fclose(fin);
		delete[] frame;
		cvReleaseMat(&mat);
		cvReleaseMat(&newmat);
		cvReleaseMat(&backup);
	}
};








int main(void)
{
	HRESULT hr = NuiCreateSensorByIndex(0, &m_pNuiSensor);
	if (FAILED(hr)) cout << "create sensor failed." << endl;

	WCHAR *id = m_pNuiSensor->NuiDeviceConnectionId();
	HANDLE m_hNextDepthFrameEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
	
	hr = m_pNuiSensor->NuiInitialize(NUI_INITIALIZE_FLAG_USES_DEPTH);

	if (FAILED(hr)) cout << "failed init." << endl;

	HANDLE m_pDepthStreamHandle;

	hr = m_pNuiSensor->NuiImageStreamOpen(
		NUI_IMAGE_TYPE_DEPTH,
		NUI_IMAGE_RESOLUTION_640x480,
		0,
		2,
		m_hNextDepthFrameEvent,
		&m_pDepthStreamHandle);
	
	//user near mode
	NuiImageStreamSetImageFrameFlags(m_pDepthStreamHandle, NUI_IMAGE_STREAM_FLAG_ENABLE_NEAR_MODE);

	DWORD retVal;
	NUI_IMAGE_FRAME imageFrame;

	DepthPlayer *player = NULL;
	DWORD frameWidth, frameHeight;

	while (true) {
		retVal = WaitForSingleObject(m_hNextDepthFrameEvent, 100);

		switch (retVal){
		case WAIT_OBJECT_0:
// 			cout << "get a depth frame." << endl;
			break;
		case WAIT_TIMEOUT:
			continue;
		}

		hr = m_pNuiSensor->NuiImageStreamGetNextFrame(
			m_pDepthStreamHandle,
			0,
			&imageFrame);

		INuiFrameTexture *pTexture = imageFrame.pFrameTexture;

		NUI_LOCKED_RECT lockedRect;

		pTexture->LockRect(0, &lockedRect, NULL, 0);
		if ( 0 != lockedRect.Pitch) {
			NuiImageResolutionToSize( imageFrame.eResolution, frameWidth, frameHeight );
			cout << frameWidth << " " << frameHeight << endl;
			
			if (player == NULL) {
				player = new DepthPlayer;
				player->initParamter(frameWidth, frameHeight);
			}
			player->frame = (short*)lockedRect.pBits;
			player->updateMat();
			player->showFrame();
			cvWaitKey(0);
		}
		pTexture->UnlockRect( 0 );

		m_pNuiSensor->NuiImageStreamReleaseFrame( m_pDepthStreamHandle, &imageFrame );

	}


	return 0;
}
